import { _decorator, Component, Node, Vec3, v3, UITransform, Vec2, Size, size, Widget } from 'cc';
import { BasicUI } from '../../Init/Basic/BasicUI';
import { GlobalConfig } from '../../Init/Config/GlobalConfig';
import { GlobalEnum } from '../../Init/Config/GlobalEnum';
import { GlobalTmpData } from '../../Init/Config/GlobalTmpData';
import { EventTypes } from '../../Init/Managers/EventTypes';
import { StorageSystem } from '../../Init/SystemStorage/StorageSystem';
import { LevelDataTmp } from '../../Init/SystemStorage/StorageTemp';
import { UIEnum } from '../../Init/SystemUI/UIEnum';
import { UISystem } from '../../Init/SystemUI/UISystem';
import { clog } from '../../Init/Tools/ColorLog';
import GlobalPool from '../../Init/Tools/GlobalPool';
import { Army2D } from './Army2D';
import { BasicEnemy } from './BasicEnemy';
import { BasicProp } from './BasicProp';
import { Mine2D } from './Mine2D';
import { People2D } from './People2D';
import { Tank2D } from './Tank2D';
import { TouchPlayer } from './TouchPlayer';
const { ccclass, property } = _decorator;
/**用于2D物理映射 */
@ccclass('Collision2DUI')
export class Collision2DUI extends BasicUI {
    private _lvData: LevelDataTmp = null;
    private _isRun = false;

    // #region ----------------生命周期------------
    public show(d: LevelDataTmp) {
        this._lvData = d;
        GlobalTmpData.EndArea.p2d.set(d.endArea.p);
        GlobalTmpData.EndArea.s2d.set(d.endArea.s.x, d.endArea.s.y);
        super.show(d);
    }
    protected onEvents() {
        this.on(EventTypes.RoleEvents.CheckEnemys, this.onCheckEnemys, this);
        this.on(EventTypes.EnemyEvents.ShootBullet, this.onShootBullet, this);
        this.on(EventTypes.EnemyEvents.HitPeople, this.onHitPeople, this);
        this.on(EventTypes.EnemyEvents.ShootMissile, this.onShootMissile, this);
        this.on(EventTypes.EnemyEvents.CheckEnemyByType, this.onCheckEnemyByType, this);
        //
        this.on(EventTypes.GameEvents.GameRun, this.onGameRun, this);
        this.on(EventTypes.GameEvents.GamePause, this.onGamePause, this);
        this.on(EventTypes.GameEvents.GameResume, this.onGameResume, this);

    }

    protected onEnable() {
        //
        let wg = this.node.getComponent(Widget);
        wg && wg.updateAlignment();

        this.reset();
        //数据
        this.setBarriers();
        this.setEnemys();
        this.setPlayers();
        this.setProps();
        this.setGrassGroup();
        this.setAwards();
        // 显示ui        
        UISystem.showUI(UIEnum.LevelInfoUI);

    }

    protected onDisable() {

    }

    public reset() {
        this._isRun = false;
        GlobalPool.putAllChildren(this.node);
        this.resetEnemy();
        this.resetProps();
    }

    protected update(dt) {
        if (!this._isRun || GlobalTmpData.Game.isGamePause) return;
        this.updateEnemys(dt);
        this.updateProps(dt);
        this.updatePlayer(dt);
    }

    // #endregion

    // #region ----------------障碍物2d----------
    protected setBarriers() {
        for (const key in this._lvData.colliders) {
            const arr = this._lvData.colliders[key];

            //生成2d碰撞体
            arr.forEach(b => {
                let perfabName = key + '2d';
                GlobalPool.get(perfabName, { parent: this.node, p: b.p, r: b.r, s: b.s });
            })

        }
    }
    // #endregion

    // #region ----------------玩家2d------------
    private _touchPlayer = null;
    protected setPlayers() {
        let p = GlobalTmpData.Game.isGuideLv ? v3(0, -2 / GlobalConfig.Scale2DTo3D, 0) : Vec3.ZERO;
        let player = GlobalPool.get('touchPlayer', { pos: p, parent: this.node, lvData: this._lvData });
        this._touchPlayer = player.getComponent(TouchPlayer);
    }

    protected updatePlayer(dt) {
        this._touchPlayer && this._touchPlayer.customUpdate(dt);
    }

    // #endregion

    //#region ----------------敌人------------
    private _enemyRecs: { [t: number]: { [uuid: string]: BasicEnemy } } = {}
    protected resetEnemy() {
        this._enemyRecs = {};
    }

    protected setEnemys() {
        const _s = GlobalConfig.Scale2DTo3D;
        let data: { enemyType: GlobalEnum.EnemyTypes, enemyName: string, node: Node, state: GlobalEnum.EnemyState }[] = [];
        let rot = v3();
        let _size = size();
        //生成2d碰撞体
        for (const key in this._lvData.enemys) {
            const arr = this._lvData.enemys[key];

            arr.forEach(b => {
                rot.set(b.r);
                rot.z -= 90;
                _size.set(b.s.x, b.s.y);
                let perfabName, node, cmp, enemyType;

                switch (key) {
                    case 'soldierA':
                    case 'soldierB':
                    case 'soldierC':
                    case 'soldierD':
                        if (undefined == b.isBoss) {
                            b['isBoss'] = false;
                        }
                        perfabName = 'army2d';
                        enemyType = GlobalEnum.EnemyTypes.Army;
                        //
                        node = GlobalPool.get(perfabName);
                        node.parent = this.node;
                        node.setPosition(b.p);
                        node.eulerAngles = rot;
                        if (b.isBoss) {
                            _size.x *= GlobalConfig.Enemy.BossScale;
                            _size.y *= GlobalConfig.Enemy.BossScale;
                        }
                        node.getComponent(UITransform).setContentSize(_size);
                        //
                        cmp = new Army2D(node);
                        cmp.init(key);
                        cmp.setBodySize(_size);
                        cmp.isBoss = b.isBoss;
                        if (b.isBoss) {
                            cmp.setHp();
                        }
                        break;
                    case 'peopleA':
                    case 'peopleB':
                    case 'peopleC':
                        perfabName = 'people2d';
                        enemyType = GlobalEnum.EnemyTypes.People;
                        //
                        node = GlobalPool.get(perfabName);
                        node.parent = this.node;
                        node.setPosition(b.p);
                        node.eulerAngles = rot;
                        node.getComponent(UITransform).setContentSize(_size);
                        //
                        cmp = new People2D(node);
                        cmp.isStatic = b.isStatic == undefined ? false : b.isStatic;
                        cmp.init(key);
                        cmp.setBodySize(_size);
                        //显示3d箭头指示
                        if (cmp.isStatic) {
                            this.emit(EventTypes.EffectEvents.showGuideArrow, node);
                        }

                        break;
                    case 'tankA':
                    case 'tankB':
                    case 'tankC':
                        perfabName = 'tank2d';
                        enemyType = GlobalEnum.EnemyTypes.Tank;
                        //
                        node = GlobalPool.get(perfabName);
                        node.parent = this.node;
                        node.setPosition(b.p);
                        node.eulerAngles = rot;
                        node.getComponent(UITransform).setContentSize(_size);
                        //
                        cmp = new Tank2D(node);
                        cmp.init({ parent: this.node, p: b.p, r: b.r, enemyName: key });
                        cmp.setBodySize(_size);
                        cmp.isBoss = true;
                        // cmp.setHp(b.hp || 1);
                        break;
                    default:
                        break;
                }
                if (!perfabName) {
                    clog.warn('enemy 不包含:', key);
                    return;
                }

                if (cmp && cmp.isBoss) {
                    GlobalTmpData.BossArr.push(v3(b.p));
                    if (GlobalTmpData.BossWarnRec.length > 0) {
                        //判断与前一个位置
                        const pre = GlobalTmpData.BossWarnRec[GlobalTmpData.BossWarnRec.length - 1];
                        let subZ = Math.abs(pre.p.y - b.p.y);
                        if (subZ > 1100) {
                            GlobalTmpData.BossWarnRec.push({ p: v3(b.p), isWarn: false });
                        }
                    } else {
                        GlobalTmpData.BossWarnRec.push({ p: v3(b.p), isWarn: false });
                    }
                    //从大到小排序
                    GlobalTmpData.BossWarnRec.sort((a, b) => a.p.y - b.p.y);
                }
                if (!cmp) debugger
                //同步到3D场景
                data.push(cmp.mappingProps);
                if (!this._enemyRecs[enemyType]) {
                    this._enemyRecs[enemyType] = {};
                }
                this._enemyRecs[enemyType][node.uuid] = cmp;
                //
            })
        }
        this.emit(EventTypes.Mapping3DEvents.SetEnemys, data);
    }

    protected updateEnemys(dt) {
        for (const key in this._enemyRecs) {
            const rec = this._enemyRecs[key];
            for (const uuid in rec) {
                const e = rec[uuid];
                if (e && e.node.active) {
                    e.update(dt);
                } else {
                    delete rec[uuid];
                }
            }
        }
    }

    // #endregion

    //#region -----------------草地------------
    //草地
    protected setGrassGroup() {
        const s = 1 / GlobalConfig.Scale2DTo3D;
        for (const key in this._lvData.models) {
            const d = this._lvData.models[key];
            switch (key) {
                case 'GrassGroup':
                    //
                    d.forEach(rec => {
                        GlobalPool.get('grassGroup2d',
                            {
                                parent: this.node, p: v3(rec.p.x * s, -rec.p.z * s, 0),
                                r: rec.r,
                                s: rec.s
                            });
                    })
                    break;

                default:
                    break;
            }
        }
    }
    //#endregion

    //#region ----------------道具------------
    protected _propPrecs: { [t: number]: { [uuid: string]: BasicProp } } = {};
    protected resetProps() {
        this._propPrecs = {};
    }
    protected setProps() {
        let data: { type: GlobalEnum.PropsType, node: Node, state?: number, data?}[] = [];

        for (const key in this._lvData.props) {
            const arr = this._lvData.props[key];
            arr.forEach(b => {
                let cmp: BasicProp, perfabName, node, propsType: GlobalEnum.PropsType;
                switch (key) {
                    case 'mine':
                        perfabName = 'mine2d';
                        propsType = GlobalEnum.PropsType.Mine;
                        node = GlobalPool.get(perfabName);
                        cmp = new Mine2D(node);
                        cmp.init(this.node, b.p, b.r);
                        break;

                    default:
                        break;
                }

                //同步到3D场景
                data.push(cmp.mappingProps);
                if (!this._propPrecs[propsType]) {
                    this._propPrecs[propsType] = {};
                }
                this._propPrecs[propsType][node.uuid] = cmp;
            })
        }


        this.emit(EventTypes.Mapping3DEvents.SetProps, data);
    }

    protected updateProps(dt) {
        for (const key in this._propPrecs) {
            const rec = this._propPrecs[key];
            for (const uuid in rec) {
                const e = rec[uuid];
                if (e && e.node.active) {
                    e.update(dt);
                } else {
                    delete rec[uuid];
                }
            }
        }
    }

    // #endregion

    //#region -----------------奖励------------
    protected setAwards() {

        // if (StorageSystem.getData().levelAssets.curLv <= 1) return;

        //宝箱
        if (this._lvData.boxMarks.length > 0) {
            //随机多个位置
            let arr = [];
            this._lvData.boxMarks.forEach(e => { arr.push(e) });

            //test
            // arr = [v3(-0.49, 100.7,)]

            for (let i = 0; i < 2; i++) {
                let randId = Math.floor(Math.random() * arr.length);
                const p = arr[randId];
                if (p) {
                    let node2d = GlobalPool.get('awardBox2d', { parent: this.node, p: p })
                    let d = { name: 'awardBox3d', p: p, data: { node: node2d } };
                    this.emit(EventTypes.Mapping3DEvents.SetAwards, d);

                    arr.splice(randId, 1);
                }
            }
        }

        //钥匙
        let keyLen = this._lvData.keyMarks.length;
        if (keyLen > 0) {
            let num = Math.floor(Math.random()) + 1;
            let n = keyLen < num ? keyLen : num;
            let arr = [];
            this._lvData.keyMarks.forEach(e => { arr.push(e) });

            for (let i = 0; i < n; i++) {
                //随机一个位置
                let index = Math.floor(Math.random() * arr.length);
                let p = arr[index];
                arr.splice(index, 1);
                if (p) {
                    let node2d = GlobalPool.get('awardKey2d', { parent: this.node, p: p })
                    let d = { name: 'awardKey3d', p: p, data: { node: node2d } };
                    this.emit(EventTypes.Mapping3DEvents.SetAwards, d);
                }
            }
        }
    }

    //#endregion

    // #region ----------------事件------------
    private tmpV3 = v3();

    protected onGameRun() {
        if (this._isRun) return;
        this._isRun = true;
    }

    onGamePause() {
        let peopleRecs = this._enemyRecs[GlobalEnum.EnemyTypes.People];
        if (!peopleRecs) return;
        for (const key in peopleRecs) {
            const cmp = peopleRecs[key] as People2D;
            cmp.pause();
        }
    }

    onGameResume() {
        let peopleRecs = this._enemyRecs[GlobalEnum.EnemyTypes.People];
        if (!peopleRecs) return;
        for (const key in peopleRecs) {
            const cmp = peopleRecs[key] as People2D;
            cmp.resume();
        }
    }

    /**检测指定位置+范围+类型的敌人 */
    protected onCheckEnemyByType(d: { p: Vec3, r: number, types: number[], out: { [t: number]: BasicEnemy[] } }) {
        for (const key in this._enemyRecs) {
            const _type = +key;
            if (d.types.indexOf(_type) < 0) break;
            const rec = this._enemyRecs[key];
            for (const uuid in rec) {
                const enemy = rec[uuid];
                if (enemy && enemy.hp > 0 && enemy.state !== GlobalEnum.EnemyState.Death) {
                    const p = enemy.node.position;
                    if (p.y >= d.p.y - d.r && p.y <= d.p.y + d.r &&
                        p.x >= d.p.x - d.r && p.x <= d.p.x + d.r) {
                        const dist = this.tmpV3.set(p).subtract(d.p).length();
                        if (dist <= d.r) {
                            if (!d.out[_type]) {
                                d.out[_type] = [];
                            }
                            d.out[_type].push(enemy);
                            break;
                        }
                    }
                }
            }
        }
    }

    //检测指定位置+范围的所有敌人  返回最近的一个
    protected onCheckEnemys(d: { p: Vec3, r: number, outEnemy: BasicEnemy }) {
        let minDist = 9999;
        d.outEnemy = null;
        for (const key in this._enemyRecs) {
            const rec = this._enemyRecs[key];
            for (const uuid in rec) {
                const enemy = rec[uuid];
                if (enemy && enemy.aimNum > 0 && enemy.state !== GlobalEnum.EnemyState.Death) {
                    const dist = this.tmpV3.set(enemy.node.position).subtract(d.p).length();
                    if (dist <= d.r && dist < minDist) {
                        minDist = dist;
                        d.outEnemy = enemy;
                        break;
                    }
                }
            }
        }
    }
    /**发射子弹 */
    protected onShootBullet(d: { t: GlobalEnum.BulletType, p: Vec3, h: number, direc: Vec2, atk: number, parent?}) {
        d.parent = this.node;
        GlobalPool.get(d.t, d);
    }
    /**射中平民 */
    protected onHitPeople(uuid: string, cb?) {
        if (this._enemyRecs[GlobalEnum.EnemyTypes.People] && this._enemyRecs[GlobalEnum.EnemyTypes.People][uuid]) {
            const people = this._enemyRecs[GlobalEnum.EnemyTypes.People][uuid];
            if (people.hp > 0) {
                people.byAtk();
                cb && cb(true);
            }
        }
        cb && cb(false);
    }
    /**发射导弹2d */
    protected onShootMissile(d: { p: Vec3, toP: Vec3, atk: number, t: number }) {
        let e = GlobalPool.get('missile2d', d);
        e.parent = this.node;
    }

    // #endregion
}

